#ifndef CONTAINER_HPP_
#define CONTAINER_HPP_

#include <string>

#include "no.hpp"
#include "error.h"

template <class T>
class container
{
public:

	container();

	container(const container<T>&);

	~container();

	void
	push( const T& );

	void
	pop();

	T
	getInfo();
	
	

	void
	clear();

	bool
	isEmpty();

	container<T>&
	operator= ( const container<T>& );
	
protected:

	void
	copy( const container<T>& );

	noh<T>*
	cursor;
	
private:


};


/***********************************************
 * 
 *        Implementations...
 * 
 * *********************************************/



template <class T>
container<T>::container()
{
	this->cursor = 0;
}

template <class T>
container<T>::container(const container<T>& _toCopy)
{
	this->cursor = 0;

	this->copy( _toCopy );
}

template <class T>
container<T>::~container()
{
	this->clear();
}

template <class T> void
container<T>::push(const T& _info)
{
	noh<T>*
	newNoh = new noh<T>(_info);
	
	if (this->cursor == 0)
	{
		this->cursor= newNoh;
	}
	else
	{
		if (this->cursor->getAnterior() != 0)
		{
			noh<T>*
			nohAnterior = this->cursor->getAnterior();
			
			nohAnterior->setPosterior( newNoh );
			
			newNoh->setAnterior( nohAnterior );
			
		}
		newNoh->setPosterior( this->cursor );
		
		this->cursor->setAnterior(newNoh);
		
		this->cursor = newNoh;
	}
}

template <class T> void
container<T>::pop()
{
	if (! this->isEmpty() )
	{
		if (this->cursor->getPosterior() == 0 && this->cursor->getAnterior() == 0)
		{
			delete this->cursor;
			this->cursor = 0;
		}
		else if (this->cursor->getAnterior() == 0 && this->cursor->getPosterior() != 0)
		{
			noh<T>*
			temp = this->cursor;
			
			this->cursor = this->cursor->getPosterior();
			this->cursor->setAnterior(0);
			
			delete temp;
		}
		else if (this->cursor->getAnterior() != 0 && this->cursor->getPosterior() == 0)
		{
			noh<T>*
			temp = this->cursor;
			
			this->cursor = this->cursor->getAnterior();
			this->cursor->setPosterior(0);
			
			delete temp;
			temp = 0;
		}
		else
		{
			noh<T>*
			nohPosterior = this->cursor->getPosterior();

			noh<T>*
			nohAnterior = this->cursor->getAnterior();

			nohPosterior->setAnterior( nohAnterior );
			nohAnterior->setPosterior( nohPosterior);

			delete this->cursor;
			this->cursor = nohPosterior;
		}
	}
	else
	{
		const std::string
		message = "ops... trying to pop an empty list";

		error*
		e = new error(message);
	
		throw e;
	}
}

template <class T> T
container<T>::getInfo()
{
	if (! this->isEmpty())
	{
		return this->cursor->getInfo();
	}
	
	const std::string
	message = "ops... trying to retrieve from an empty list!";

	error* 
	e = new error(message);

	throw e;
}

template <class T> void
container<T>::clear()
{
	while (! this->isEmpty())
	{
		this->pop();
	}
	this->cursor = 0;
}

template <class T> bool
container<T>::isEmpty()
{
	if (this->cursor != 0)
	{
		return false;
	}
	else
	{
		return true;
	}
}



template<class T> container<T>&
container<T>::operator= ( const container<T>& _toEqualize )
{
	delete this->cursor;
	this->cursor = 0;
	
	this->copy(_toEqualize);
	
	return *this;
}

/********************************************
 * 
 *    Protected methods
 * 
 * ******************************************/

template <class T> void
container<T>::copy( const container<T>& _toCopy)
{
	noh<T>*
	toCopyCursor = _toCopy.cursor;
		
	noh<T>*
	CursorOriginalPosition = toCopyCursor;
	
	if( toCopyCursor->getPosterior() == 0 && toCopyCursor->getAnterior() != 0)
	{

		while (toCopyCursor != 0 )
		{
			noh<T>*
			temp = new noh<T>;

			temp->setInfo( toCopyCursor->getInfo() );

			if (this->cursor == 0)
			{
				this->cursor = temp;
			}
			else
			{
				this->cursor->setAnterior( temp );
				temp->setPosterior (this->cursor );
			}
			toCopyCursor = toCopyCursor->getAnterior();
		}

	}
	else if (toCopyCursor->getAnterior() == 0 && toCopyCursor->getPosterior() != 0)
	{
		while (toCopyCursor != 0 )
		{
			noh<T>*
			temp = new noh<T>;

			temp->setInfo( toCopyCursor->getInfo() );

			if (this->cursor == 0)
			{
				this->cursor = temp;
			}
			else
			{
				this->cursor->setPosterior( temp );
				temp->setAnterior( this->cursor );
			}
			toCopyCursor = toCopyCursor->getPosterior();
		}		

	}
	this->cursor = CursorOriginalPosition;
}
 
#endif /*CONTAINER_HPP_*/
